package com.github.live.base;

import android.app.Application;
import com.github.live.plugins.PluginsLoader;
import com.github.live.plugins.base.ChannelsRegister;
import com.github.live.plugins.base.EpgRegister;
import com.github.live.plugins.base.IjkCodecRegister;
import com.github.live.util.ExecutorServiceUtil;
import com.github.live.util.ILogger;
import com.github.live.util.LogFactory;
import com.github.livebase.event.Event;
import com.github.livebase.event.EventBus;
import com.github.livebase.event.SimpleEventBus;
import com.github.livebase.log.AbstractLogger;
import com.github.livebase.log.ConsoleLogger;
import com.github.livebase.log.LoggerDefinition;
import com.github.livebase.log.LoggerDefinitionUtil;
import com.github.livebase.log.LoggerException;
import com.github.livebase.log.LoggerFactory;
import com.github.livebase.plugins.PluginFactory;
import com.github.livebase.plugins.PluginException;
import com.github.livebase.plugins.RegisterInfo;
import com.github.livebase.util.LiveContext;
import com.github.livebase.util.base.CollectionsUtil;
import com.github.server.interfaces.HttpApplication;
import com.github.server.interfaces.ResourceMapping;
import com.orhanobut.hawk.Hawk;
import com.orhanobut.hawk.LogInterceptor;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

import me.jessyan.autosize.AutoSizeConfig;
import me.jessyan.autosize.unit.Subunits;
import tv.danmaku.ijk.media.player.IjkLogger;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import tv.danmaku.ijk.media.player.pragma.DebugLog;

/**
 * @author pj567
 * @date :2020/12/17
 * @description:
 */
public class LiveApplication extends Application {
    private static String TAG = LiveApplication.class.getSimpleName();
    private static LiveContext context;

    public static LiveContext getContext() {
        return context;
    }
    public static PluginFactory getPluginContext() {
        return context.getPluginFactory();
    }

    @Override
    public void onCreate() {
        // 最先初始化
        GloabConfig gloabConfig = new GloabConfig(this);
        initLogger(gloabConfig.getLogLevel());
        ExecutorServiceUtil.init(gloabConfig.getThreadPoolCoreSize());
        initParams();

        SimpleEventBus.init(LogFactory.getLogger(), gloabConfig.getEventBusThreadSize());
        int level = gloabConfig.getLogLevel() < 0 ? AbstractLogger.LEVEL_INFO : gloabConfig.getLogLevel();
        context = new LiveContext(this, level);

        LogFactory.trance(LiveApplication.class, "application starting");

        super.onCreate();
        try {
            getPluginContext().register(Arrays.asList(
                    new RegisterInfo(IjkCodecRegister.class, "ijkCodec", null),
                    new RegisterInfo(ChannelsRegister.class, "channel", null),
                    new RegisterInfo(EpgRegister.class, "updater", new String[]{EventBus.EVENT_CHANGE_DATE}, true)
            ));
            PluginsLoader loader = new PluginsLoader(context, getPluginContext());
            loader.load(context.getExternalFilesDir(""));
        } catch (PluginException e) {
            LogFactory.warn(TAG, e, "initial plugin error");
        }

        if (gloabConfig.isHttpEnable()) {
            initHttpService();
        }

        SimpleEventBus.getDefault()
                .publish(new Event(EventBus.EVENT_APP_READY));
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        SimpleEventBus.getDefault()
                .publish(new Event(EventBus.EVENT_APP_EXIT));
    }

    private void initParams() {
        // Hawk
        Hawk.init(this).setLogInterceptor(new LogInterceptor() {
            @Override
            public void onLog(String message) {
                ConsoleLogger.getLogger().debug("Hawk", message);
            }
        }).build();
        AutoSizeConfig.getInstance().setCustomFragment(true).getUnitsManager()
                .setSupportDP(false)
                .setSupportSP(false)
                .setSupportSubunits(Subunits.MM);
    }


    private void initHttpService() {
        HttpApplication application = new com.github.server.Application(10532);
        try {
            // 静态资源映射
            List<ResourceMapping> handlers = context.getPluginFactory().get("httpHandlers");
            CollectionsUtil.foreach(handlers, (h) -> {
                application.registerHandler(h);
            });
            application.start();
        }
        catch(IOException e) {
            e.printStackTrace();
            application.stop();
        }
    }

    private void initLogger(int level) {
        Thread.setDefaultUncaughtExceptionHandler(new ProxyUncaughtExceptionHandler(this));
        try {
            // 注册最顶层日志处理，注册失败直接退出程序
            registerILogger("", "default.log", level);
        } catch (LoggerException e) {
            throw new RuntimeException(e);
        }
        try(InputStream input = getAssets().open("logger.xml")) {
            List<LoggerDefinition> definitions = LoggerDefinitionUtil.readFromXml(input);
            CollectionsUtil.foreach(definitions, d -> {
                d.addParameter("file", LiveContext.getLogFile(this, String.valueOf(d.getParamValue("file"))), File.class);
            });
            if (level >= 0) {
                CollectionsUtil.foreach(definitions, (definition -> {
                    definition.addParameter("level", level, int.class);
                }));
            }
            LoggerFactory.registerLoggers(definitions);
        } catch (IOException e) {
            LoggerFactory.getLogger(LiveApplication.class).warn(TAG, e, "init logger error");
        }

        // 日志等级映射
        IjkMediaPlayer.setLogLevel(setLogLevel(level));
        if (level <= 0) {
            return;
        }
        IjkMediaPlayer.setIjkLogger(new IjkLogger() {
            @Override
            public void v(String tag, String msg) {
                DebugLog.v(tag, msg);
            }

            @Override
            public void d(String tag, String msg) {
                DebugLog.d(tag, msg);
            }

            @Override
            public void i(String tag, String msg) {
                DebugLog.i(tag, msg);
            }

            @Override
            public void w(String tag, String msg) {
                DebugLog.w(tag, msg);
            }

            @Override
            public void e(String tag, String msg) {
                DebugLog.e(tag, msg);
            }
        });
    }

    public void registerILogger(String packageName, String logFile, int level) throws LoggerException {
        if (level < 0) {
            level = AbstractLogger.LEVEL_ERROR;
        }
        ILogger.registerILogger(packageName, level, LiveContext.getLogFile(this, logFile));
    }

    private static int setLogLevel(int liveLevel) {
        if (liveLevel > 0) {
            return liveLevel - 1;
        }
        return IjkMediaPlayer.IJK_LOG_SILENT;
    }
}